<?php

namespace Lib\DB;

class Sqlite {
	private $_aServer = array ();
	private $_aMaster = array ();
	private $_rResult;

	public function __construct($aConf) {
		$this->connect ( $aConf );
	}

	public function connect($aConf, $sServer = 'db') {
		try {
			if ($aConf ['name'] == '@memroy') {
				$sDsn = 'sqlite::memroy:';
			} else {
				$sDsn = 'sqlite:' . $aConf ['name'];
			}
			$oDbh = new \PDO ( $sDsn, $aConf ['user'], $aConf ['password'] );
			$oDbh->setAttribute ( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
			$aConf ['table'] = array ();
			$this->_aServer [$sServer] = $aConf;
			$this->_aMaster [$sServer] = $oDbh;
			return $oDbh;
		} catch ( \Exception $e ) {
			echo $e->getMessage ();
		}
	}

	public function disconnect($sServer = 'db') {
		unset ( $this->_aMaster [$sServer] );
	}

	public function exec($sSql, $aValue = null, $sServer = 'db') {
		try {
			$oServer = $this->_aMaster [$sServer];
			$rResult = $oServer->prepare ( $sSql );
			if (is_array ( $aValue )) {
				$i = 1;
				foreach ( $aValue as $sKey => $val ) {
					if (is_int ( $sKey )) {
						$rResult->bindParam ( $i ++, $aValue [$sKey] );
					} else {
						$rResult->bindParam ( ':' . $sKey, $aValue [$sKey] );
					}
				}
			} elseif ($aValue !== null) {
				$rResult->bindParam ( 1, $aValue );
			}
			$rResult->execute ();
			return $rResult->rowCount ();
		} catch ( \Exception $e ) {
			$e->getMessage ();
		}
		return false;
	}

	public function query($sSql, $aValue = null, $sServer = 'db') {
		$this->_rResult = null;
		
		try {
			$oServer = $this->_getSlave ( $sServer, false );
			$rResult = $oServer->prepare ( $sSql );
			if (is_array ( $aValue )) {
				$i = 1;
				foreach ( $aValue as $sKey => $val ) {
					if (is_int ( $sKey )) {
						$rResult->bindParam ( $i ++, $aValue [$sKey] );
					} else {
						$rResult->bindParam ( ':' . $sKey, $aValue [$sKey] );
					}
				}
			} elseif ($aValue !== null) {
				$rResult->bindParam ( 1, $aValue );
			}
			$rResult->execute ();
			$this->_rResult = $rResult;
			return $rResult;
		} catch ( \Exception $e ) {
			echo $sSql;
			echo $e->getMessage ();
		}
		return false;
	}

	public function getRow($rResult = null, $sModel = 'assoc') {
		if ($rResult === null) {
			$rResult = $this->_rResult;
		}
		
		if ($rResult === null) {
			return false;
		}
		
		try {
			switch (strtolower ( $sModel )) {
				case 'assoc' :
					$sModel = \PDO::FETCH_ASSOC;
					break;
				case 'num' :
					$sModel = \PDO::FETCH_NUM;
					break;
				default :
					$sModel = \PDO::FETCH_BOTH;
			}
			return $rResult->fetch ( $sModel );
		} catch ( \Exception $e ) {
			$e->getMessage ();
		}
		
		return false;
	}

	private function _getSlave($sServer) {
		return $this->_aMaster [$sServer];
	}

	public function getOne($sSql, $aValue = null, $sServer = 'db') {
		$this->query ( $sSql, $aValue, $sServer );
		$aRow = $this->getRow ();
		if ($aRow) {
			if (count ( $aRow ) == 1) {
				return $aRow [key ( $aRow )];
			} else {
				return $aRow;
			}
		} else {
			return false;
		}
	}

	public function getTableInfo($sTable, $sServer = 'db') {
		list ( $sTableName, $sAliasName ) = explode ( ' ', $sTable );
		if (! array_key_exists ( $sTableName, $this->_aServer [$sServer] ['table'] )) {
			$sSql = 'SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ?';
			$sCreateSql = $this->getOne ( $sSql, array (
					'table',
					$sTableName 
			), $sServer );
			$sCreateSql = substr ( $sCreateSql, strpos ( $sCreateSql, '(' ) + 1, - 1 );
			$aFieldInfo = explode ( ',', $sCreateSql );
			foreach ( $aFieldInfo as $v ) {
				if (preg_match ( '/"(.+?)"/', $v, $m )) {
					$aRow ['Field'] = $m [1];
				}
				if (preg_match ( '/PRIMARY KEY/i', $v, $m )) {
					$aRow ['Key'] = 'PRI';
				} else {
					$aRow ['Key'] = '';
				}
				$aRows [] = $aRow;
			}
			foreach ( $aRows as $aRow ) {
				$this->_aServer [$sServer] ['table'] [$sTableName] ['field'] [$aRow ['Field']] = $aRow;
				if ($sAliasName) {
					$this->_aServer [$sServer] ['table'] [$sTableName] ['field'] [$sAliasName . '.' . $aRow ['Field']] = $aRow;
				}
				if ($aRow ['Key'] == 'PRI') {
					$this->_aServer [$sServer] ['table'] [$sTableName] ['pri'] [] = $aRow ['Field'];
				}
			}
			
			list ( $sKey ) = each ( $this->_aServer [$sServer] ['table'] [$sTableName] ['field'] );
			if (strrpos ( $sKey, '_' )) {
				list ( $sPre ) = explode ( '_', $sKey );
				$this->_aServer [$sServer] ['table'] [$sTableName] ['pre'] = $sPre ? $sPre . '_' : '';
			}
			if ($sAliasName) {
				$this->_aServer [$sServer] ['table'] [$sTableName] ['alias'] = $sAliasName;
			}
		}
		return $this->_aServer [$sServer] ['table'] [$sTableName];
	}

	public function getArray($sTable, $sKey = 'id', $sName = 'name', $aWhere = array(), $aSort = array(), $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		if ($aTableInfo) {
			$sFullTable = $this->_aServer [$sServer] ['pre'] . $sTable;
			if ($sKey == null) {
				$sSql = 'SELECT ' . $aTableInfo ['pre'] . $sName . ' name FROM `' . $sFullTable . '`';
			} else {
				$sSql = 'SELECT ' . $aTableInfo ['pre'] . $sKey . ' id,' . $aTableInfo ['pre'] . $sName . ' name FROM `' . $sFullTable . '`';
				$sGroup = ' GROUP BY ' . $aTableInfo ['pre'] . $sKey;
			}
			$aWhere = $this->_getWhere ( $sTable, $aWhere, $sServer );
			$aValue = $aWhere ['value'];
			$aArray = array ();
			$sSql .= $aWhere ['sql'];
			$sSql .= $sGroup;
			if (! empty ( $aSort )) {
				$aSqlSort = array ();
				foreach ( $aSort as $sRow ) {
					list ( $sSortField, $sSortType ) = explode ( ':', $sRow );
					if ($sSortType) {
						$aSqlSort [] = $sSortField . ' ' . $sSortType;
					} else {
						$aSqlSort [] = $sSortField;
					}
				}
				$sSql .= ' ORDER BY ' . implode ( ',', $aSqlSort );
			} elseif (array_key_exists ( 'sort', $aTableInfo ['field'] )) {
				$sSql .= ' ORDER BY sort';
			} else {
				$sSql .= ' ORDER BY name';
			}
			$aData = $this->query ( $sSql, $aValue );
			while ( ($aRow = $this->getRow ()) !== false ) {
				if ($sKey == null) {
					$aArray [] = $aRow ['name'];
				} else {
					$aArray [$aRow ['id']] = $aRow ['name'];
				}
			}
			return $aArray;
		} else {
			return false;
		}
	}

	/**
	 *
	 * @param 查询返回列表 $aParam
	 *        	table:表名，多表使用数组：name：表名，alias：别名为空时使用表名
	 *        	field:返回的字段：字段名作为key是value为字段别名
	 *        	nofield:不返回的字段
	 *        	key:返回数组的key使用字段名，默认为数字
	 *        	where:查询条件
	 *        	server:数据库服务器
	 * @return array
	 */
	public function ls($aParam) {
		$aParam ['server'] = $aParam ['server'] ? $aParam ['server'] : 'db';
		if (is_array ( $aParam ['table'] )) {
			$aTableInfo = array (
					'field' => array () 
			);
			foreach ( $aParam ['table'] as $v ) {
				if (! $v ['alias']) {
					$v ['alias'] = $v ['name'];
				}
				$aInfo = $this->getTableInfo ( $v ['name'] . ' ' . $v ['alias'], $aParam ['server'] );
				$aTableInfo ['field'] += $aInfo ['field'];
				if ($this->_aServer [$aParam ['server']] ['pre'] . $v ['name'] == $this->_aServer [$aParam ['server']] ['pre'] . $v ['alias']) {
					$aTables [] = $this->_aServer [$aParam ['server']] ['pre'] . $v ['name'];
				} else {
					$aTables [] = $this->_aServer [$aParam ['server']] ['pre'] . $v ['name'] . ' ' . $v ['alias'];
				}
			}
		} else {
			$aTableInfo = $this->getTableInfo ( $aParam ['table'] . ' ' . $aParam ['alias'], $aParam ['server'] );
		}
		if (is_array ( $aParam ['left_join'] )) {
			foreach ( $aParam ['left_join'] as $v ) {
				$aJoinInfo = $this->getTableInfo ( $v ['table'] . ' ' . $v ['alias'], $aParam ['server'] );
				$aTableInfo ['field'] += $aJoinInfo ['field'];
			}
		}
		
		if ($aTableInfo) {
			if ($aTables) {
				$sFullTable = implode ( ', ', $aTables );
			} else {
				$sFullTable = '`' . $this->_aServer [$aParam ['server']] ['pre'] . $aParam ['table'] . '` ' . $aTableInfo ['alias'];
			}
			if (is_array ( $aParam ['field'] )) {
				foreach ( $aParam ['field'] as $k => $v ) {
					if (! intval ( $k ) && array_key_exists ( $k, $aTableInfo ['field'] )) {
						if (strpos ( $k, '.' )) {
							list ( $t, $f ) = explode ( '.', $k );
							$aSqlField [] = '`' . $t . '`.`' . $f . '` AS `' . $v . '`';
						} else {
							$aSqlField [] = '`' . $k . '` AS `' . $v . '`';
						}
					} elseif (array_key_exists ( $v, $aTableInfo ['field'] )) {
						if (strpos ( $v, '.' )) {
							list ( $t, $f ) = explode ( '.', $v );
							$aSqlField [] = '`' . $t . '`.`' . $f . '`';
						} else {
							$aSqlField [] = '`' . $v . '`';
						}
					} elseif (strpos ( $v, '*' ) !== false) {
						if (strpos ( $v, '.' )) {
							list ( $t, $f ) = explode ( '.', $v );
							$aSqlField [] = '`' . $t . '`.*';
						} else {
							$aSqlField [] = '*';
						}
					}
				}
				if ($aSqlField) {
					$sSqlField = implode ( ', ', $aSqlField );
				} else {
					$sSqlField = '*';
				}
			} else {
				$sSqlField = '*';
			}
			$sSql = 'SELECT ' . $sSqlField . ' FROM ' . $sFullTable;
			
			$aWhere = $this->_getWhereByTableInfo ( $aTableInfo, $aParam ['where'], $aParam ['server'] );
			$aValue = $aWhere ['value'];
			$sSql .= $aWhere ['sql'];
			
			if (is_array ( $aParam ['sort'] )) {
				if (is_array ( $aParam ['sort'] )) {
					foreach ( $aParam ['sort'] as $k => $v ) {
						if (array_key_exists ( $k, $aTableInfo ['field'] )) {
							if (! $v || strtolower ( $v ) == 'asc') {
								$aSort [] = $k . ' ASC';
							} else {
								$aSort [] = $k . ' DESC';
							}
						}
					}
				}
				if ($aSort) {
					$sSql .= ' ORDER BY ' . implode ( ', ', $aSort );
				}
			} elseif ($aParam ['sort']) {
				$sSql .= ' ORDER BY ' . $aParam ['sort'];
			}
			
			if ($aParam ['key'] && array_key_exists ( $aTableInfo ['pre'] . $aParam ['key'], $aTableInfo ['field'] )) {
				$sReturnKey = $aParam ['key'];
			} else {
				$sReturnKey = '';
			}
			
			$iCount = $this->_getItems ( $sSql, $aValue, $aParam ['server'] );
			$sItemsField = $aParam ['items_field'] ? $aParam ['items_field'] : 'items';
			$sCountField = $aParam ['count_field'] ? $aParam ['count_field'] : 'count';
			if ($iCount == 0) {
				return array (
						$sItemsField => array (),
						$sCountField => $iCount 
				);
			}
			if ($aParam ['limit']) {
				$iStart = intval ( $aParam ['start'] );
				if ($iStart > $iCount) {
					return array (
							$sItemsField => array (),
							$sCountField => $iCount 
					);
				}
				$sSql .= ' LIMIT ' . $iStart . ', ' . $aParam ['limit'];
			}
			$rRes = $this->query ( $sSql, $aValue );
			while ( ($aRow = $this->getRow ( $rRes )) !== false ) {
				$aOne = array ();
				if ($aTableInfo ['pre'] || $aParam ['value'] || $aParam ['alias'] || $aParam ['nofield']) {
					foreach ( $aRow as $sKey => $sValue ) {
						if ($aTableInfo ['pre']) {
							$sKey = preg_replace ( '/^' . $aTableInfo ['pre'] . '/', '', $sKey );
						}
						if (is_array ( $aParam ['nofield'] ) && in_array ( $sKey, $aParam ['nofield'] )) {
							continue;
						}
						$aOne [$sKey] = $sValue;
						if ($aParam ['value'] && array_key_exists ( $sKey, $aParam ['value'] )) {
							$aOne [$sKey . '_value'] = $aParam ['value'] [$sKey] [$sValue];
							$sKey = $sKey . '_value';
						}
						if ($aParam ['alias']) {
							if (array_key_exists ( $sKey, $aParam ['alias'] )) {
								$aOne [$aParam ['alias'] [$sKey]] = $aOne [$sKey];
								unset ( $aOne [$sKey] );
							}
						}
					}
				} else {
					$aOne = $aRow;
				}
				if (is_array ( $aParam ['format'] )) {
					$aOne = $this->_formatData ( $aOne, $aParam ['format'] );
				}
				if ($aOne [$sReturnKey]) {
					$aData [$sItemsField] [$aOne [$sReturnKey]] = $aOne;
				} else {
					$aData [$sItemsField] [] = $aOne;
				}
			}
			$aData [$sCountField] = $iCount;
			return $aData;
		}
	}

	public function _formatData($aRow, $aFormats) {
		global $o;
		foreach ( $aFormats as $aFormat ) {
			if ($aFormat ['eval']) {
				$sEval = '$aRow [$aFormat [\'return_field\']] = ' . preg_replace ( '/\$this/', '$aRow', $aFormat ['eval'] ) . ';';
				eval ( $sEval );
			} elseif ($aFormat ['model']) {
				$oClass = $o->$aFormat ['model'] ['class'];
				$aParam = array ();
				if (is_array ( $aFormat ['model'] ['param'] )) {
					foreach ( $aFormat ['model'] ['param'] as $v ) {
						if ($v == '$this') {
							$aParam [] = $aRow;
						} elseif (array_key_exists ( $v, $aRow )) {
							$aParam [] = $aRow [$v];
						}
					}
				}
				$aRow [$aFormat ['return_field']] = call_user_func_array ( array (
						$oClass,
						$aFormat ['model'] ['method'] 
				), $aParam );
			}
		}
		return $aRow;
	}

	private function _getItems($sSql, $aValue, $sServer) {
		$sSql = preg_replace ( '/[\r\n]+/', ' ', $sSql );
		$sSql = preg_replace ( '/(select).*[\s\r\n]+(from.*)/is', '$1 COUNT(1) $2', $sSql );
		$iPos = strripos ( $sSql, 'ORDER BY' );
		if ($iPos !== false) {
			$sSql = substr ( $sSql, 0, $iPos );
		}
		$this->query ( $sSql, $aValue, $sServer );
		if (strripos ( $sSql, 'GROUP BY' )) {
			$rows = $this->getRows ();
			return count ( $rows );
		} else {
			return $this->getResult ();
		}
	}

	public function getRows($rResult = null, $sModel = 'assoc') {
		if ($rResult === null) {
			$rResult = $this->_rResult;
		}
		
		if ($rResult === null) {
			return false;
		}
		
		try {
			switch (strtolower ( $sModel )) {
				case 'assoc' :
					$sModel = \PDO::FETCH_ASSOC;
					break;
				case 'num' :
					$sModel = \PDO::FETCH_NUM;
					break;
				default :
					$sModel = \PDO::FETCH_BOTH;
			}
			return $rResult->fetchAll ( $sModel );
		} catch ( \Exception $e ) {
			$e->getMessage ();
		}
		return false;
	}

	public function getResult($iIndex = 0, $rResult = null) {
		if ($rResult === null) {
			$rResult = $this->_rResult;
		}
		
		if ($rResult === null) {
			return false;
		}
		
		return $rResult->fetchColumn ( $iIndex );
	}

	public function clear($sTable, $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		if ($aTableInfo) {
			$sSql = 'TRUNCATE ' . $this->_aServer [$sServer] ['pre'] . $sTable;
			$this->exec ( $sSql, null, $sServer );
			return true;
		} else {
			return false;
		}
	}

	public function getInsertId($sServer = 'db') {
		$oServer = $this->_aMaster [$sServer];
		return $oServer->lastInsertId ();
	}

	public function insert($sTable, $aData, $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		if ($aTableInfo) {
			$sFullTable = $this->_aServer [$sServer] ['pre'] . $sTable;
			$i = 0;
			foreach ( $aData as $sKey => $sRow ) {
				if (array_key_exists ( $aTableInfo ['pre'] . $sKey, $aTableInfo ['field'] )) {
					if ($i == 0) {
						$sField = '`' . $aTableInfo ['pre'] . $sKey . '`';
						$sValue = '?';
					} else {
						$sField .= ', `' . $aTableInfo ['pre'] . $sKey . '`';
						$sValue .= ', ?';
					}
					$aValue [] = $sRow;
					$i ++;
				}
			}
			$sSql = 'INSERT INTO `' . $sFullTable . '` (' . $sField . ') VALUES (' . $sValue . ')';
			if ($this->exec ( $sSql, $aValue, $sServer )) {
				return $this->getInsertId ( $sServer );
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	public function update($sTable, $aData, $aWhere = array(), $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		if ($aTableInfo) {
			$sFullTable = $this->_aServer [$sServer] ['pre'] . $sTable;
			$aValue = array ();
			$i = 0;
			foreach ( $aData as $sKey => $sRow ) {
				if (array_key_exists ( $aTableInfo ['pre'] . $sKey, $aTableInfo ['field'] )) {
					$sKey = $aTableInfo ['pre'] . $sKey;
					if (preg_match ( '/@/', $sRow )) {
						$sRow = preg_replace ( '/@this/', '`' . $sKey . '`', $sRow );
						if ($i == 0) {
							$sField = '`' . $sKey . '` = ' . $sRow;
						} else {
							$sField .= ', `' . $sKey . '` = ' . $sRow;
						}
					} else {
						if ($i == 0) {
							$sField = '`' . $sKey . '` = ?';
						} else {
							$sField .= ', `' . $sKey . '` = ?';
						}
						$aValue [] = $sRow;
					}
					$i ++;
				}
			}
			$sSql = 'UPDATE `' . $sFullTable . '`  SET ' . $sField;
			$aWhere = $this->_getWhere ( $sTable, $aWhere, $sServer );
			if ($aWhere ['sql']) {
				$sSql .= $aWhere ['sql'];
				$aValue = array_merge ( $aValue, $aWhere ['value'] );
			}
			return $this->exec ( $sSql, $aValue, $sServer );
		} else {
			return false;
		}
	}

	public function get($sTable, $iId, $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		if ($aTableInfo) {
			$sFullTable = $this->_aServer [$sServer] ['pre'] . $sTable;
			if (is_array ( $iId )) {
				$aWhere = $this->_getWhere ( $sTable, $iId, $sServer );
				$aValue = $aWhere ['value'];
				$sWhere = $aWhere ['sql'];
			} elseif (count ( $aTableInfo ['pri'] ) == 1) {
				$sWhere = 'WHERE ' . $aTableInfo ['pri'] [0] . ' = ?';
				$aValue = $iId;
			} else {
				return false;
			}
			$sSql = 'SELECT * FROM `' . $sFullTable . '`' . $sWhere;
			$aData = $this->getOne ( $sSql, $aValue, $sServer );
			if (is_array ( $aData ) && $aTableInfo ['pre']) {
				foreach ( $aData as $sKey => $sRow ) {
					unset ( $aData [$sKey] );
					$sKey = preg_replace ( '/^' . $aTableInfo ['pre'] . '/', '', $sKey );
					$aData [$sKey] = $sRow;
				}
			}
			return $aData;
		}
		
		return false;
	}

	public function getAll($sTable, $aWhere = array(), $aField = array(), $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		if ($aTableInfo) {
			$sFullTable = $this->_aServer [$sServer] ['pre'] . $sTable;
			$aWhere = $this->_getWhere ( $sTable, $aWhere, $sServer );
			$aValue = $aWhere ['value'];
			$sWhere = $aWhere ['sql'];
			if (is_array ( $aField )) {
				foreach ( $aField as $v ) {
					if (array_key_exists ( $v, $aTableInfo ['field'] )) {
						$aSqlField [] = $v;
					}
				}
				if ($aSqlField) {
					$sSqlField = implode ( ', ', $aSqlField );
				} else {
					$sSqlField = '*';
				}
			} else {
				$sSqlField = '*';
			}
			$sSql = 'SELECT ' . $sSqlField . ' FROM `' . $sFullTable . '`' . $sWhere;
			$this->query ( $sSql, $aValue, $sServer );
			while ( ($aRow = $this->getRow ()) !== false ) {
				$aData [] = $aRow;
			}
			return $aData;
		}
	}

	public function delete($sTable, $iId, $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		if ($aTableInfo) {
			$sTable = $this->_aServer [$sServer] ['pre'] . $sTable;
			if (is_array ( $iId )) {
				foreach ( $iId as $sKey => $sRow ) {
					if (array_key_exists ( $aTableInfo ['pre'] . $sKey, $aTableInfo ['field'] )) {
						if (is_array ( $sRow )) {
							$aWhere [] = $aTableInfo ['pre'] . $sKey . ' IN (?' . str_repeat ( ',?', count ( $sRow ) - 1 ) . ')';
							$aVaule = array_merge ( $aVaule, $sRow );
						} else {
							$sValue = trim ( $sRow );
							if (preg_match ( '/^(<>|>|<|like)(.+?)$/i', $sValue, $aMatch )) {
								$aWhere [] = $aTableInfo ['pre'] . $sKey . $aMatch [1] . ' ?';
								$aVaule [] = trim ( $aMatch [2] );
							} else {
								$aWhere [] = $aTableInfo ['pre'] . $sKey . ' = ?';
								$aVaule [] = $sRow;
							}
						}
					}
				}
			} elseif (count ( $aTableInfo ['pri'] ) == 1) {
				$aWhere [] = $aTableInfo ['pri'] [0] . ' = ?';
				$aVaule = $iId;
			} else {
				return false;
			}
			$sSql = 'DELETE FROM `' . $sTable . '` WHERE ' . implode ( ' AND ', $aWhere );
			return $this->exec ( $sSql, $aVaule, $sServer );
		}
		
		return false;
	}

	private function _getWhereByTableInfo($aTableInfo, $aData) {
		$aWhere = array ();
		$aVaule = array ();
		if (is_array ( $aData )) {
			foreach ( $aData as $sKey => $sRow ) {
				if (array_key_exists ( $aTableInfo ['pre'] . $sKey, $aTableInfo ['field'] )) {
					if (is_array ( $sRow )) {
						$aWhere [] = $aTableInfo ['pre'] . $sKey . ' IN (?' . str_repeat ( ',?', count ( $sRow ) - 1 ) . ')';
						$aVaule = array_merge ( $aVaule, $sRow );
					} else {
						$sValue = trim ( $sRow );
						if (preg_match ( '/^(<>|>=|<=|>|<|like)(.+?)$/i', $sValue, $aMatch )) {
							$aWhere [] = $aTableInfo ['pre'] . $sKey . ' ' . $aMatch [1] . ' ?';
							$aVaule [] = trim ( $aMatch [2] );
						} elseif (preg_match ( '/^@(.+)$/i', $sValue, $aMatch )) {
							$aWhere [] = $aTableInfo ['pre'] . $sKey . ' = ' . $aMatch [1];
						} else {
							$aWhere [] = $aTableInfo ['pre'] . $sKey . ' = ?';
							$aVaule [] = $sRow;
						}
					}
				} elseif (is_int ( $sKey )) {
					$aWhere [] = $sRow;
				}
			}
		}
		
		if ($aWhere) {
			return array (
					'sql' => ' WHERE ' . implode ( ' AND ', $aWhere ),
					'value' => $aVaule 
			);
		} else {
			return array (
					'sql' => '',
					'value' => $aVaule 
			);
		}
	}

	private function _getWhere($sTable, $aData, $sServer = 'db') {
		$aTableInfo = $this->getTableInfo ( $sTable, $sServer );
		$aWhere = array ();
		$aVaule = array ();
		if (is_array ( $aData )) {
			foreach ( $aData as $sKey => $sRow ) {
				if (array_key_exists ( $aTableInfo ['pre'] . $sKey, $aTableInfo ['field'] )) {
					if (is_array ( $sRow )) {
						$aWhere [] = $aTableInfo ['pre'] . $sKey . ' IN (?' . str_repeat ( ',?', count ( $sRow ) - 1 ) . ')';
						$aVaule = array_merge ( $aVaule, $sRow );
					} else {
						$sValue = trim ( $sRow );
						if (preg_match ( '/^(<>|>|<|like)(.+?)$/i', $sValue, $aMatch )) {
							$aWhere [] = $aTableInfo ['pre'] . $sKey . ' ' . $aMatch [1] . ' ?';
							$aVaule [] = trim ( $aMatch [2] );
						} elseif (preg_match ( '/^@(\s+)$/i', $sValue, $aMatch )) {
							$aWhere [] = $aTableInfo ['pre'] . $sKey . ' = ' . $aMatch [1];
						} else {
							$aWhere [] = $aTableInfo ['pre'] . $sKey . ' = ?';
							$aVaule [] = $sRow;
						}
					}
				}
			}
		}
		
		if ($aWhere) {
			return array (
					'sql' => ' WHERE ' . implode ( ' AND ', $aWhere ),
					'value' => $aVaule 
			);
		} else {
			return array (
					'sql' => '',
					'value' => $aVaule 
			);
		}
	}

	public function begin($sServer = 'db') {
		$oServer = $this->_selectServer ( $sServer );
		$oServer->beginTransaction ();
	}

	public function commit($sServer = 'db') {
		$oServer = $this->_selectServer ( $sServer );
		$oServer->commit ();
	}
}

?>